package com.wave.common.core;

import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
import cn.dev33.satoken.exception.SaTokenContextException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.service.IService;
import com.wave.common.model.BaseEntity;
import org.springframework.scheduling.annotation.Async;

import java.util.Collection;
import java.util.Map;


public interface IWaveService<T> extends IService<T> {

    @Override
    default boolean saveOrUpdateBatch(Collection<T> entities, int batchSize) {
        entitiesBatchFix(entities);
        return IService.super.saveOrUpdateBatch(entities, batchSize);
    }

    @Override
    default boolean saveOrUpdateBatch(Collection<T> entities) {
        entitiesBatchFix(entities);
        return IService.super.saveOrUpdateBatch(entities);
    }

    @Override
    default boolean saveOrUpdate(T entity) {
        entityFix(entity);
        return IService.super.saveOrUpdate(entity);
    }

    @Override
    default boolean saveBatch(Collection<T> entities, int batchSize) {
        entitiesBatchFix(entities);
        return IService.super.saveBatch(entities, batchSize);
    }

    @Override
    default boolean saveBatch(Collection<T> entities) {
        entitiesBatchFix(entities);
        return IService.super.saveBatch(entities);
    }

    @Override
    default boolean save(T entity) {
        entityFix(entity);
        return IService.super.save(entity);
    }

    @Override
    default boolean updateById(T entity) {
        entityFix(entity);
        return IService.super.updateById(entity);
    }

    @Override
    default boolean updateById(T entity, boolean ignoreNulls) {
        entityFix(entity);
        return IService.super.updateById(entity, ignoreNulls);
    }

    @Override
    default boolean update(T entity, Map<String, Object> query) {
        entityFix(entity);
        return IService.super.update(entity, query);
    }

    @Override
    default boolean update(T entity, QueryWrapper query) {
        entityFix(entity);
        return IService.super.update(entity, query);
    }

    @Override
    default boolean update(T entity, QueryCondition condition) {
        entityFix(entity);
        return IService.super.update(entity, condition);
    }

    @Override
    default boolean updateBatch(Collection<T> entities) {
        entitiesBatchFix(entities);
        return IService.super.updateBatch(entities);
    }

    @Override
    default boolean updateBatch(Collection<T> entities, boolean ignoreNulls) {
        entitiesBatchFix(entities);
        return IService.super.updateBatch(entities, ignoreNulls);
    }

    @Override
    default boolean updateBatch(Collection<T> entities, int batchSize) {
        entitiesBatchFix(entities);
        return IService.super.updateBatch(entities, batchSize);
    }

    @Override
    default boolean updateBatch(Collection<T> entities, int batchSize, boolean ignoreNulls) {
        entitiesBatchFix(entities);
        return IService.super.updateBatch(entities, batchSize, ignoreNulls);
    }

    private void entityFix(T entity) {

        if (ObjectUtil.isEmpty(entity)) {
            return;
        }
        if (!(entity instanceof BaseEntity temp)) {
            return;
        }
        boolean login = isLogin();
        if (!login) {
            return;
        }
        long currentUser = StpUtil.getLoginIdAsLong();
        if (ObjectUtil.isEmpty(currentUser)) {
            return;
        }
        if (ObjectUtil.isEmpty(temp.getId())) {
            temp.setCreateUser(currentUser);
        }
        temp.setUpdateUser(currentUser);
    }

    private void entitiesBatchFix(Collection<T> entities) {
        if (entities.isEmpty()) {
            return;
        }
        Object o = entities.toArray()[0];
        if (!(o instanceof BaseEntity)) {
            return;
        }
        boolean login = isLogin();
        if (!login) {
            return;
        }
        long currentUser = StpUtil.getLoginIdAsLong();
        if (ObjectUtil.isEmpty(currentUser)) {
            return;
        }
        entities.stream().peek(item -> {
            BaseEntity temp = (BaseEntity) item;
            if (ObjectUtil.isEmpty(temp.getId())) {
                temp.setCreateUser(currentUser);
            }
            temp.setUpdateUser(currentUser);
        }).close();
    }

    private boolean isLogin() {
        boolean result;
        try {
            result = StpUtil.isLogin();
        } catch (SaTokenContextException e) {
            result = false;
        }
        return result;
    }

}
